---@class HY_Utility
local HY = {}

---获取Mod是否启用
---@param room Room
---@return boolean
function HY.CheckEnabled(room)
    local packs = { "touhou_standard", "touhou_answers", "touhou_animals", "touhou_epic", "touhou_hell", "touhou_ship", "touhou_cards" }
    if room.settings == nil then
        return false
    end
    for _, pack in ipairs(packs) do
        if not table.contains(room.settings["disabledPack"], pack) then
            return true
        end
    end
    return false
end

---@param func fun(value:any, key:any, array:table):boolean
function table:any(func)
    if type(self) ~= "table" then
        return false
    end
    for k, v in pairs(self) do
        if func(v, k, self) then
            return true
        end
    end
    return false
end

---@param other table?
function table:sequencialEquals(other)
    if type(self) ~= "table" or type(other) ~= "table" then
        return false
    end
    if table.realLength(self) ~= table.realLength(other) then
        return false
    end
    for i = 1, table.realLength(self), 1 do
        local _, a = table.tryGet(self, i)
        local _, b = table.tryGet(other, i)
        if type(a) == "table" and type(b) == "table" and not table.sequencialEquals(a, b) then
            return false
        elseif a ~= b then
            return false
        end
    end
    return true
end

--#region table

---@param index integer
---@return boolean
---@return any
function table:tryGet(index)
    local i = 1
    for _, value in pairs(self) do
        if i == index then
            return true, value
        else
            i = i + 1
        end
    end
    return false, nil
end

function table:realLength()
    local result = 0
    for _, _ in pairs(self) do
        result = result + 1
    end
    return result
end

---@param other table
---@return table
function table:except(other)
    self = self or {}
    other = other or {}
    local result = table.cloneWithoutClass(self)
    for _, value in pairs(other) do
        table.removeOne(result, value)
    end
    return result
end

---@param func fun(value:any,key:any):number
---@return number
function table:sum(func)
    local result = 0
    for key, value in pairs(self) do
        result = result + func(value, key)
    end
    return result
end

---@return boolean
function table:same()
    if type(self) ~= "table" then
        return false
    end
    local value
    local first = true
    for _, v in pairs(self) do
        if first then
            value = v
            first = false
        elseif value ~= v then
            return false
        end
    end
    return true
end

--#endregion

--#region math

---@param value number
---@param min number
---@param max number
function math.clamp(value, min, max)
    return math.min(math.max(value, min), max)
end

--#endregion

--#region string

---@param str string
---@param str2 string
---@return string
function string.Remove(str, str2)
    local result = str:gsub(str2, "")
    return result
end

---@param str string
---@param str2 string
---@return boolean
function string.With(str, str2)
    local str3 = str:gsub(str2, "")
    return str ~= str3
end

---@param str string
---@return string
function string.RemoveLabel(str)
    local result = str:gsub("<[^>]+>", "")
    return result
end

---@param str string
---@return boolean
function string.WithLabel(str)
    local str2 = str:gsub("<[^>]+>", "")
    return str ~= str2
end

--#endregion

---更新明置卡牌的显示状态
---@param room Room
function HY.UpdatePublicizedCards(room)
    local totalMarks = {}
    for _, id in ipairs(Fk:getAllCardIds()) do
        local card = Fk:getCardById(id, true)
        if card and room:getCardArea(card) == Card.PlayerHand and HY.IsCardPublicized(card) then
            local owner = room:getCardOwner(card)
            if owner then
                totalMarks[owner.id] = totalMarks[owner.id] or {}
                table.insertIfNeed(totalMarks[owner.id], id)
            end
        end
    end
    for _, t in ipairs(room.players) do
        if totalMarks[t.id] == nil then
            room:setPlayerMark(t, "@$card_publicize", 0)
        else
            local marks = totalMarks[t.id]
            if not table.sequencialEquals(marks, t:getMark("@$card_publicize")) then
                room:setPlayerMark(t, "@$card_publicize", marks)
            end
        end
    end
end

---将手牌替换为临时牌，不发生实际移动
---@param player ServerPlayer
---@param cards integer[]|Card[]
function HY.ReplaceHandCardToTemp(player, cards)
    local room = player.room
    local cardIds = {}
    for _, card in ipairs(cards) do
        if type(card) == "number" then
            table.insertIfNeed(cardIds, card)
        elseif card.class and card:isInstanceOf(Card) then
            if #card.subcards > 0 then
                for _, id in ipairs(card.subcards) do
                    table.insertIfNeed(cardIds, id)
                end
            elseif not card:isVirtual() then
                table.insertIfNeed(cardIds, card.id)
            end
        end
    end
    if #cardIds == 0 then
        return
    end
    local moves = {}
    local moveInfos = {}
    -- process old
    if player.tag["tempMoveOld"] then
        for _, info in ipairs(player.tag["tempMoveOld"]) do
            table.insert(moves, {
                from = player.id,
                to = info.from,
                toArea = info.fromArea,
                moveInfo = { {
                    cardId = info.id,
                    fromArea = Card.PlayerHand,
                } },
                moveReason = fk.ReasonJustMove,
                specialName = info.fromSpecialName,
            })
        end
        player:doNotify("MoveCards", { moves, 0 })
    end
    moves = {}
    for _, id in ipairs(cardIds) do
        local fromOwner = room:getCardOwner(id)
        if fromOwner then
            fromOwner = fromOwner.id
        end
        local fromArea = room:getCardArea(id)
        local specialName = player:getPileNameOfId(id)
        table.insert(moves, {
            from = fromOwner,
            to = player.id,
            toArea = Card.PlayerHand,
            moveInfo = { {
                cardId = id,
                fromArea = fromArea,
                fromSpecialName = specialName
            } },
            moveReason = fk.ReasonJustMove,
        })
        table.insert(moveInfos, {
            id = id,
            from = fromOwner,
            fromArea = fromArea,
            fromSpecialName = specialName,
        })
    end
    -- remove hand
    HY.RemoveHandCard(player)
    -- fromArea to hand
    player:doNotify("MoveCards", { moves, 0 })
    player.tag["tempMoveOld"] = moveInfos
end

---复原手牌，只适用于使用ReplaceHandCardTemp后
---@param player ServerPlayer
function HY.ReverseHandCardFromTemp(player)
    if player.tag["tempMoveOld"] == nil then
        return
    end
    --hand to toArea
    local moves = {}
    for _, info in ipairs(player.tag["tempMoveOld"]) do
        table.insert(moves, {
            from = player.id,
            to = info.from,
            toArea = info.fromArea,
            moveInfo = { {
                cardId = info.id,
                fromArea = Card.PlayerHand,
            } },
            moveReason = fk.ReasonJustMove,
            specialName = info.fromSpecialName,
        })
    end
    player:doNotify("MoveCards", { moves, 0 })
    --reverse hand
    HY.ReverseHandCard(player)
end

---将手牌替换为临时牌，不发生实际移动（新版）
---@param player ServerPlayer
---@param cards integer[]|Card[]
function HY.ReplaceHandCardToTempNew(player, cards)
    HY.RemoveHandCard(player)
    HY.AddCardsToTemp(player, cards)
end

---复原手牌（新版）
---@param player ServerPlayer
function HY.ReverseHandCardFromTempNew(player)
    HY.ReverseHandCard(player)
    HY.RemoveTempCards(player)
end

---仅移除手牌
---@param player ServerPlayer
function HY.RemoveHandCard(player)
    local hands = player:getCardIds("h")
    player.tag["tempMove"] = player.tag["tempMove"] or {}
    if not player.tag["tempMove"]["hands"] then
        player.tag["tempMove"]["hands"] = hands
        -- hand to temp pile
        player:doNotify("MoveCards", { { {
            from = player.id,
            to = player.id,
            toArea = Card.PlayerSpecial,
            specialName = "#tempMove",
            moveInfo = table.map(hands, function(id) return { cardId = id, fromArea = Card.PlayerHand } end),
            moveReason = fk.ReasonJustMove,
        } }, 0 })
    end
end

---仅恢复手牌
---@param player ServerPlayer
function HY.ReverseHandCard(player)
    if not player.tag["tempMove"] then
        return
    end
    if not player.tag["tempMove"]["hands"] then
        return
    end

    local hands = player.tag["tempMove"]["hands"]
    -- temp pile to hand
    player:doNotify("MoveCards", { { {
        from = player.id,
        to = player.id,
        toArea = Card.PlayerHand,
        moveInfo = table.map(hands, function(id) return { cardId = id, fromArea = Card.PlayerSpecial, fromSpecialName = "#tempMove" } end),
        moveReason = fk.ReasonJustMove,
    } }, 0 })
    player.tag["tempMove"]["hands"] = nil
end

---仅添加临时牌
---@param player ServerPlayer
---@param cards integer[]|Card[]
function HY.AddCardsToTemp(player, cards)
    local room = player.room
    local cardIds = {}
    for _, card in ipairs(cards) do
        if type(card) == "number" then
            table.insertIfNeed(cardIds, card)
        elseif card.class and card:isInstanceOf(Card) then
            if #card.subcards > 0 then
                for _, id in ipairs(card.subcards) do
                    table.insertIfNeed(cardIds, id)
                end
            elseif not card:isVirtual() then
                table.insertIfNeed(cardIds, card.id)
            end
        end
    end
    if #cardIds == 0 then
        return
    end

    player.tag["tempMove"] = player.tag["tempMove"] or {}

    for _, id in pairs(cardIds) do
        Fk:filterCard(id, player)
    end
    if player.tag["tempMove"]["current"] then
        for _, id in pairs(player.tag["tempMove"]["current"]) do
            Fk:filterCard(id, nil)
        end
    end
    player.tag["tempMove"]["current"] = cardIds
    room:setPlayerMark(player, "#tempMove", cardIds)
    room:delay(100)
end

---仅移除临时牌
---@param player ServerPlayer
function HY.RemoveTempCards(player)
    local room = player.room
    if not player.tag["tempMove"] then
        return
    end
    if not player.tag["tempMove"]["current"] then
        return
    end

    local current = player.tag["tempMove"]["current"]
    for _, id in ipairs(current) do
        Fk:filterCard(id, nil)
    end

    room:setPlayerMark(player, "#tempMove", 0)
    player.tag["tempMove"]["current"] = nil
    room:delay(100)
end

--- 询问一名玩家选择自己的几张牌（临时牌可见）。
---
--- 与askForDiscard类似，但是不对选择的牌进行操作就是了。
---@param player ServerPlayer @ 要询问的玩家
---@param minNum integer @ 最小值
---@param maxNum integer @ 最大值
---@param includeEquip? boolean @ 能不能选装备
---@param skillName? string @ 技能名
---@param cancelable? boolean @ 能否点取消
---@param pattern? string @ 选牌规则
---@param prompt? string @ 提示信息
---@param expand_pile? string @ 可选私人牌堆名称
---@param no_indicate? boolean @ 是否不显示指示线
---@return integer[] @ 选择的牌的id列表，可能是空的
function HY.AskForCard(player, minNum, maxNum, includeEquip, skillName, cancelable, pattern, prompt, expand_pile, no_indicate)
    if maxNum < 1 then
        return {}
    end
    cancelable = (cancelable == nil) and true or cancelable
    no_indicate = no_indicate or false
    pattern = pattern or "."

    local chosenCards = {}
    local data = {
        num = maxNum,
        min_num = minNum,
        include_equip = includeEquip,
        skillName = skillName,
        pattern = pattern,
        expand_pile = expand_pile,
    }
    prompt = prompt or ("#AskForCard:::" .. maxNum .. ":" .. minNum)
    local _, ret = player.room:askToUseActiveSkill(player, {
        skill_name = "choose_cards_skill_temp",
        prompt = prompt,
        cancelable = cancelable,
        extra_data = data,
        no_indicate = no_indicate
    })
    if ret then
        chosenCards = ret.cards
    else
        if cancelable then return {} end
        local cards = player:getCardIds("he&")
        if type(expand_pile) == "string" then
            table.insertTable(cards, player:getPile(expand_pile))
        elseif type(expand_pile) == "table" then
            table.insertTable(cards, expand_pile)
        end
        local exp = Exppattern:Parse(pattern)
        cards = table.filter(cards, function(cid)
            return exp:match(Fk:getCardById(cid))
        end)
        chosenCards = table.random(cards, minNum)
    end

    return chosenCards
end

---获得本回合弃牌堆
---@param room Room
---@return Card[]
function HY.GetTurnDiscardPile(room)
    local result = {}
    local events = room.logic:getEventsOfScope(GameEvent.MoveCards, 999, function(e)
        return table.any(e.data, function(move)
            return move.toArea == Card.DiscardPile
        end)
    end, Player.HistoryTurn)
    for _, e in ipairs(events) do
        for _, move in ipairs(e.data) do
            for _, info in ipairs(move.moveInfo) do
                if room:getCardArea(info.cardId) == Card.DiscardPile then
                    table.insertIfNeed(result, Fk:getCardById(info.cardId))
                end
            end
        end
    end
    return result
end

---假读条
---@param room Room
---@param player Player
---@param command string
function HY.FakeThinking(room, player, command)
    room:notifyMoveFocus(player, command)
    local waits = {}
    table.insertIfNeed(waits, math.random(500, 800))
    table.insertIfNeed(waits, math.random(800, 1800))
    table.insertIfNeed(waits, math.random(1800, 2500))
    local weight = math.random(1, 10)
    if weight <= 3 then
        room:delay(waits[1])
    elseif weight > 3 and weight <= 8 then
        room:delay(waits[2])
    else
        room:delay(waits[3])
    end
end

---获得借刀杀人的被杀角色
---@param room Room
---@param tos TargetGroup
---@return ServerPlayer?
function HY.GetCollateralSlashTarget(room, tos)
    if type(tos) ~= "table" then
        return nil
    end
    for _, innerTable in pairs(tos) do
        if #innerTable == 2 and type(innerTable[2]) == "number" then
            return room:getPlayerById(innerTable[2])
        end
    end
    return nil
end

---设置借刀目标
---@param targets ServerPlayer[]|integer[]
---@param slashTarget ServerPlayer|integer
---@return table
function HY.SetCollateralTargets(targets, slashTarget)
    local tos = {}
    if #targets == 0 then
        return {}
    end
    local targetIds = {}
    if type(targets[1]) == "number" then
        table.insertTableIfNeed(targetIds, targets)
    else
        table.insertTableIfNeed(targetIds, table.map(targets, Util.IdMapper))
    end
    if type(slashTarget) == "nil" then
        return {}
    end
    local slashTargetId
    if slashTarget.class and slashTarget:isInstanceOf(ServerPlayer) then
        slashTargetId = slashTarget.id
    else
        slashTargetId = slashTarget
    end
    for i = 1, #targetIds, 1 do
        table.insertIfNeed(tos, { targetIds[i] })
        table.insertIfNeed(tos, { slashTargetId })
    end
    return tos
end

-- 获取目标对应的角色（不包括死亡角色且不计算重复目标）
---@param room Room
---@param data AimData|UseCardData @ 目标数据
---@return ServerPlayer[] @ 返回目标角色player的id列表
function HY.GetActualUseTargets(room, data)
    if data.tos == nil then return {} end
    local targets = {}
    local tos = data:getAllTargets()
    for _, p in ipairs(room.alive_players) do
        if table.contains(tos, p) then
            table.insertIfNeed(targets, p)
        end
    end
    return targets
end

--为使用牌增减目标
---@param player ServerPlayer @ 执行的玩家
---@param num integer @ 可选的目标数
---@param can_minus boolean @ 是否可减少
---@param distance_limited boolean @ 是否受距离限制
---@param prompt string @ 提示信息
---@param skillName string @ 技能名
---@param data AimData|UseCardData @ 数据
---@return ServerPlayer[]
function HY.AskForAddTarget(player, num, can_minus, distance_limited, prompt, skillName, data)
    local room = player.room
    local targets = data:getExtraTargets({
        bypass_distances = not distance_limited
    })
    local result = {}
    if #targets > 0 then
        table.insertTable(result, room:askToChoosePlayers(player, {
            targets = targets,
            min_num = 1,
            max_num = num,
            prompt = prompt,
            skill_name = skillName,
            target_tip_name = "addandcanceltarget_tip",
            extra_data = table.map(data:getAllTargets(), Util.IdMapper)
        }))
    end
    num = num - #result
    local origin_targets = HY.GetActualUseTargets(room, data)
    if #result == 0 then
        num = math.min(num, #origin_targets - 1)
    end
    if can_minus and num > 0 then
        table.insertTable(result, room:askToChoosePlayers(player, {
            targets = origin_targets,
            min_num = 1,
            max_num = num,
            prompt = prompt,
            skill_name = skillName,
            target_tip_name = "addandcanceltarget_tip",
            extra_data = table.map(data:getAllTargets(), Util.IdMapper)
        }))
    end
    return result
end

---@param data AimData|UseCardData @ 目标数据
---@param targets ServerPlayer[]|ServerPlayer @ 目标
function HY.ChangeTarget(data, targets)
    if targets.class and targets:isInstanceOf(ServerPlayer) then
        targets = { targets }
    end
    for _, target in ipairs(targets) do
        if table.contains(data:getAllTargets(), target) then
            -- 根据data类型决定调用哪个方法
            if data.cancelTarget then
                data:cancelTarget(target) -- AimData
            else
                data:removeTarget(target) -- UseCardData
            end
        else
            data:addTarget(target)
        end
    end
end

---设置卡牌为明置状态<br>
---在卡牌发生移动后自动取消明置
---@param room Room
---@param cards Card[]|Card|integer[]|integer 卡牌
---@param isRemove boolean|nil 是否为暗置
---@param prohibitUpdate boolean|nil 是否不自动更新显示
function HY.SetCardPublicize(room, cards, isRemove, prohibitUpdate)
    local cardIds = Card:getIdList(cards)
    for _, id in pairs(cardIds) do
        local card = Fk:getCardById(id, true)
        if card ~= nil then
            if isRemove == nil or not isRemove then
                room:setCardMark(card, "@@card_publicize", 1)
            else
                room:setCardMark(card, "@@card_publicize", 0)
            end
        end
    end
    if prohibitUpdate == nil or not prohibitUpdate then
        HY.UpdatePublicizedCards(room)
    end
end

---卡牌是否明置<br>
---判定区与装备区的牌默认明置
---@param card Card
---@return boolean
function HY.IsCardPublicized(card)
    if card == nil then
        return false
    end
    if card:isVirtual() then
        if #card.subcards > 0 and table.every(card.subcards, function(id)
                return HY.IsCardPublicized(Fk:getCardById(id))
            end) then
            return true
        else
            return false
        end
    end
    if card:getMark("@@card_publicize") > 0 then
        return true
    end
    if Fk:currentRoom():getCardArea(card) == Card.PlayerEquip or Fk:currentRoom():getCardArea(card) == Card.PlayerJudge then
        return true
    end
    return false
end

---获得一名角色明置的牌
---@param room Room
---@param player Player
---@param containsEquip boolean|nil
---@return integer[]
function HY.GetPublicizedCards(room, player, containsEquip)
    local result = {}
    local flag = containsEquip and "he" or "h"
    for _, id in ipairs(player:getCardIds(flag)) do
        local card = Fk:getCardById(id)
        if HY.IsCardPublicized(card) then
            table.insertIfNeed(result, id)
        end
    end
    return result
end

---获得卡牌类型（可获得单字版本）
---@param card Card
---@param brief boolean
---@return string
function HY.GetCardTypeString(card, brief)
    local t = card.type
    if brief then
        if t == Card.TypeBasic then
            return "basic_brief"
        elseif t == Card.TypeTrick then
            return "trick_brief"
        elseif t == Card.TypeEquip then
            return "equip_brief"
        end
    else
        if t == Card.TypeBasic then
            return "basic"
        elseif t == Card.TypeTrick then
            return "trick"
        elseif t == Card.TypeEquip then
            return "equip"
        end
    end
    return "notype"
end

Fk:loadTranslationTable {
    ["basic_brief"] = "基",
    ["trick_brief"] = "锦",
    ["equip_brief"] = "装",
    ["basic_brief_red"] = "<font color=red>基</font>",
    ["trick_brief_red"] = "<font color=red>锦</font>",
    ["equip_brief_red"] = "<font color=red>装</font>",
    ["@@card_publicize"] = "明置",
    ["@$card_publicize"] = "明置",
    ["hy_card_publicize"] = "一名角色区域内牌面信息对所有角色可见的牌称为明置的牌，明置的牌发生区域移动后可见性重置。"
}

local hy_originKingdoms = {
    "ten_k",
    "chi_k",
    "jin_k",
}

---变更势力
---@param target ServerPlayer
---@param room Room
---@param skillName string|nil
---@param sendLog boolean|nil
---@param cancelable boolean|nil
function HY.AskForChangeKingdom(target, room, skillName, sendLog, cancelable)
    local kingdoms = table.clone(hy_originKingdoms)
    table.removeOne(kingdoms, target.kingdom)
    if cancelable then
        table.insertIfNeed(kingdoms, "Cancel")
    end
    local prompt
    if cancelable then
        prompt = "hy_change_kingdom"
    else
        prompt = "hy_change_kingdom_force"
    end
    local result = room:askToChoice(target, {
        choices = kingdoms,
        skill_name = skillName,
        prompt = prompt,
    })
    if result ~= "Cancel" then
        room:changeKingdom(target, result, sendLog)
    end
end

Fk:loadTranslationTable {
    ["hy_change_kingdom"] = "你可以变更势力",
    ["hy_change_kingdom_force"] = "你须变更势力",
}

---获取所有空装备栏
---@param target Player
function HY.GetEmptyEquipSlots(target)
    local results = target:getAvailableEquipSlots()
    for _, id in pairs(target:getEquipments(Card.SubtypeWeapon)) do
        table.removeOne(results, Player.WeaponSlot)
    end
    for _, id in pairs(target:getEquipments(Card.SubtypeArmor)) do
        table.removeOne(results, Player.ArmorSlot)
    end
    for _, id in pairs(target:getEquipments(Card.SubtypeDefensiveRide)) do
        table.removeOne(results, Player.DefensiveRideSlot)
    end
    for _, id in pairs(target:getEquipments(Card.SubtypeOffensiveRide)) do
        table.removeOne(results, Player.OffensiveRideSlot)
    end
    for _, id in pairs(target:getEquipments(Card.SubtypeTreasure)) do
        table.removeOne(results, Player.TreasureSlot)
    end
    return results
end

---@param room Room
---@param datas table<ServerPlayer, AskToDiscardParams>[]
---@return table<Player, integer[]>
function HY.AskToDiscardSameTime(room, datas)
    local skill_name = nil
    local players = {}
    local toAsk = {}
    local ret = {}
    for _, data in ipairs(datas) do
        data[2] = table.clone(data[2])
        local player = data[1]
        local params = data[2]
        table.insertIfNeed(players, player)
        if skill_name == nil then
            skill_name = params.skill_name
        end

        params.cancelable = (params.cancelable == nil) and true or params.cancelable
        params.no_indicate = params.no_indicate or false
        params.pattern = params.pattern or "."
        params.prompt = params.prompt or ("#AskForDiscard:::" .. params.max_num .. ":" .. params.min_num)
        local canDiscards = table.filter(
            player:getCardIds { Player.Hand, params.include_equip and Player.Equip or nil }, function(id)
                local checkpoint = true
                local card = Fk:getCardById(id)

                local status_skills = Fk:currentRoom().status_skills[ProhibitSkill] or Util.DummyTable
                for _, skill in ipairs(status_skills) do
                    if skill:prohibitDiscard(player, card) then
                        return false
                    end
                end
                if params.skill_name == "phase_discard" then
                    status_skills = Fk:currentRoom().status_skills[MaxCardsSkill] or Util.DummyTable
                    for _, skill in ipairs(status_skills) do
                        if skill:excludeFrom(player, card) then
                            return false
                        end
                    end
                end

                if params.pattern ~= "" then
                    checkpoint = checkpoint and (Exppattern:Parse(params.pattern):match(card))
                end
                return checkpoint
            end
        )
        if params.min_num >= #canDiscards and not params.cancelable then
            ret[player] = canDiscards
        else
            local extra_data = {
                num = params.max_num,
                min_num = params.min_num,
                include_equip = params.include_equip,
                skillName = params.skill_name,
                pattern = params.pattern,
            }
            local askData = { "discard_skill", params.prompt, params.cancelable, extra_data }
            table.insertIfNeed(toAsk, { player, askData })
        end
    end
    if #toAsk == 0 then
        return ret
    end

    Fk.currentResponseReason = skill_name
    local req = Request:new(table.map(toAsk, function(ask)
        return ask[1]
    end), "AskForUseActiveSkill")
    req.focus_text = skill_name
    req.focus_players = players

    for _, ask in ipairs(toAsk) do
        req:setData(ask[1], ask[2])
        req:setDefaultReply(ask[1], ret[ask[1]] or {})
    end
    req:ask()
    Fk.currentResponseReason = nil
    local discards = {}
    for _, ask in ipairs(toAsk) do
        local ids = {}
        local result = req:getResult(ask[1])
        if result ~= "" then
            if result.card then
                ids = result.card.subcards
            else
                ids = result
            end
        end
        ret[ask[1]] = ids
    end
    for p, ids in pairs(ret) do
        local params = table.filter(datas, function(data)
            return data[1] == p
        end)[1][2]
        if not params.skip then
            table.insertIfNeed(discards, {
                ids = ids,
                from = p,
                toArea = Card.DiscardPile,
                moveReason = fk.ReasonDiscard,
                proposer = p,
                skillName = params.skill_name,
            })
        end
    end
    if #discards > 0 then
        room:moveCards(table.unpack(discards))
    end
    return ret
end

return HY
